// ======================= DOM Utility Functions from PastryKit =============================== //

// Sure, we could use jQuery or XUI for these, 
// but these are concise and will work with plain vanilla JS

Element.prototype.hasClassName = function (a) {
    return new RegExp("(?:^|\\s+)" + a + "(?:\\s+|$)").test(this.className);
};

Element.prototype.addClassName = function (a) {
    if (!this.hasClassName(a)) {
        this.className = [this.className, a].join(" ");
    }
};

Element.prototype.removeClassName = function (b) {
    if (this.hasClassName(b)) {
        var a = this.className;
        this.className = a.replace(new RegExp("(?:^|\\s+)" + b + "(?:\\s+|$)", "g"), " ");
    }
};

Element.prototype.toggleClassName = function (a) {
    this[this.hasClassName(a) ? "removeClassName" : "addClassName"](a);
};

// ======================= Modernizr =============================== //

/* Modernizr 2.0.6 (Custom Build) | MIT & BSD
 * Build: http://www.modernizr.com/download/#-csstransforms3d-iepp-cssclasses-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes-load
 */
;
window.Modernizr=function(a,b,c){
    function C(a,b){
        var c=a.charAt(0).toUpperCase()+a.substr(1),d=(a+" "+o.join(c+" ")+c).split(" ");
        return B(d,b)
        }
        function B(a,b){
        for(var d in a)if(k[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1
        }
        function A(a,b){
        return!!~(""+a).indexOf(b)
        }
        function z(a,b){
        return typeof a===b
        }
        function y(a,b){
        return x(n.join(a+";")+(b||""))
        }
        function x(a){
        k.cssText=a
        }
        var d="2.0.6",e={},f=!0,g=b.documentElement,h=b.head||b.getElementsByTagName("head")[0],i="modernizr",j=b.createElement(i),k=j.style,l,m=Object.prototype.toString,n=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),o="Webkit Moz O ms Khtml".split(" "),p={},q={},r={},s=[],t=function(a,c,d,e){
        var f,h,j,k=b.createElement("div");
        if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:i+(d+1),k.appendChild(j);
        f=["&shy;","<style>",a,"</style>"].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);
        return!!h
        },u,v={}.hasOwnProperty,w;
    !z(v,c)&&!z(v.call,c)?w=function(a,b){
        return v.call(a,b)
        }:w=function(a,b){
        return b in a&&z(a.constructor.prototype[b],c)
        };
        
    var D=function(a,c){
        var d=a.join(""),f=c.length;
        t(d,function(a,c){
            var d=b.styleSheets[b.styleSheets.length-1],g=d.cssRules&&d.cssRules[0]?d.cssRules[0].cssText:d.cssText||"",h=a.childNodes,i={};
            while(f--)i[h[f].id]=h[f];
            e.csstransforms3d=i.csstransforms3d.offsetLeft===9
            },f,c)
        }([,["@media (",n.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join("")],[,"csstransforms3d"]);
    p.csstransforms3d=function(){
        var a=!!B(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);
        a&&"webkitPerspective"in g.style&&(a=e.csstransforms3d);
        return a
        };
        
    for(var E in p)w(p,E)&&(u=E.toLowerCase(),e[u]=p[E](),s.push((e[u]?"":"no-")+u));x(""),j=l=null,a.attachEvent&&function(){
        var a=b.createElement("div");
        a.innerHTML="<elem></elem>";
        return a.childNodes.length!==1
        }()&&function(a,b){
        function s(a){
            var b=-1;
            while(++b<g)a.createElement(f[b])
                }
                a.iepp=a.iepp||{};
        
        var d=a.iepp,e=d.html5elements||"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",f=e.split("|"),g=f.length,h=new RegExp("(^|\\s)("+e+")","gi"),i=new RegExp("<(/*)("+e+")","gi"),j=/^\s*[\{\}]\s*$/,k=new RegExp("(^|[^\\n]*?\\s)("+e+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),l=b.createDocumentFragment(),m=b.documentElement,n=m.firstChild,o=b.createElement("body"),p=b.createElement("style"),q=/print|all/,r;
        d.getCSS=function(a,b){
            if(a+""===c)return"";
            var e=-1,f=a.length,g,h=[];
            while(++e<f){
                g=a[e];
                if(g.disabled)continue;
                b=g.media||b,q.test(b)&&h.push(d.getCSS(g.imports,b),g.cssText),b="all"
                }
                return h.join("")
            },d.parseCSS=function(a){
            var b=[],c;
            while((c=k.exec(a))!=null)b.push(((j.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(h,"$1.iepp_$2")+c[4]);
            return b.join("\n")
            },d.writeHTML=function(){
            var a=-1;
            r=r||b.body;
            while(++a<g){
                var c=b.getElementsByTagName(f[a]),d=c.length,e=-1;
                while(++e<d)c[e].className.indexOf("iepp_")<0&&(c[e].className+=" iepp_"+f[a])
                    }
                    l.appendChild(r),m.appendChild(o),o.className=r.className,o.id=r.id,o.innerHTML=r.innerHTML.replace(i,"<$1font")
            },d._beforePrint=function(){
            p.styleSheet.cssText=d.parseCSS(d.getCSS(b.styleSheets,"all")),d.writeHTML()
            },d.restoreHTML=function(){
            o.innerHTML="",m.removeChild(o),m.appendChild(r)
            },d._afterPrint=function(){
            d.restoreHTML(),p.styleSheet.cssText=""
            },s(b),s(l);
        d.disablePP||(n.insertBefore(p,n.firstChild),p.media="print",p.className="iepp-printshim",a.attachEvent("onbeforeprint",d._beforePrint),a.attachEvent("onafterprint",d._afterPrint))
        }(a,b),e._version=d,e._prefixes=n,e._domPrefixes=o,e.testProp=function(a){
        return B([a])
        },e.testAllProps=C,e.testStyles=t,e.prefixed=function(a){
        return C(a,"pfx")
        },g.className=g.className.replace(/\bno-js\b/,"")+(f?" js "+s.join(" "):"");
    return e
    }(this,this.document),function(a,b,c){
    function k(a){
        return!a||a=="loaded"||a=="complete"
        }
        function j(){
        var a=1,b=-1;
        while(p.length- ++b)if(p[b].s&&!(a=p[b].r))break;
        a&&g()
        }
        function i(a){
        var c=b.createElement("script"),d;
        c.src=a.s,c.onreadystatechange=c.onload=function(){
            !d&&k(c.readyState)&&(d=1,j(),c.onload=c.onreadystatechange=null)
            },m(function(){
            d||(d=1,j())
            },H.errorTimeout),a.e?c.onload():n.parentNode.insertBefore(c,n)
        }
        function h(a){
        var c=b.createElement("link"),d;
        c.href=a.s,c.rel="stylesheet",c.type="text/css";
        if(!a.e&&(w||r)){
            var e=function(a){
                m(function(){
                    if(!d)try{
                        a.sheet.cssRules.length?(d=1,j()):e(a)
                        }catch(b){
                        b.code==1e3||b.message=="security"||b.message=="denied"?(d=1,m(function(){
                            j()
                            },0)):e(a)
                        }
                    },0)
            };
            
        e(c)
        }else c.onload=function(){
        d||(d=1,m(function(){
            j()
            },0))
        },a.e&&c.onload();
    m(function(){
        d||(d=1,j())
        },H.errorTimeout),!a.e&&n.parentNode.insertBefore(c,n)
    }
    function g(){
    var a=p.shift();
    q=1,a?a.t?m(function(){
        a.t=="c"?h(a):i(a)
        },0):(a(),j()):q=0
    }
    function f(a,c,d,e,f,h){
    function i(){
        !o&&k(l.readyState)&&(r.r=o=1,!q&&j(),l.onload=l.onreadystatechange=null,m(function(){
            u.removeChild(l)
            },0))
        }
        var l=b.createElement(a),o=0,r={
        t:d,
        s:c,
        e:h
    };
    
    l.src=l.data=c,!s&&(l.style.display="none"),l.width=l.height="0",a!="object"&&(l.type=d),l.onload=l.onreadystatechange=i,a=="img"?l.onerror=i:a=="script"&&(l.onerror=function(){
        r.e=r.r=1,g()
        }),p.splice(e,0,r),u.insertBefore(l,s?null:n),m(function(){
        o||(u.removeChild(l),r.r=r.e=o=1,j())
        },H.errorTimeout)
    }
    function e(a,b,c){
    var d=b=="c"?z:y;
    q=0,b=b||"j",C(a)?f(d,a,b,this.i++,l,c):(p.splice(this.i++,0,a),p.length==1&&g());
    return this
    }
    function d(){
    var a=H;
    a.loader={
        load:e,
        i:0
    };
    
    return a
    }
    var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=r&&!s,u=s?l:n.parentNode,v=a.opera&&o.call(a.opera)=="[object Opera]",w="webkitAppearance"in l.style,x=w&&"async"in b.createElement("script"),y=r?"object":v||x?"img":"script",z=w?"img":y,A=Array.isArray||function(a){
    return o.call(a)=="[object Array]"
    },B=function(a){
    return Object(a)===a
    },C=function(a){
    return typeof a=="string"
    },D=function(a){
    return o.call(a)=="[object Function]"
    },E=[],F={},G,H;
H=function(a){
    function f(a){
        var b=a.split("!"),c=E.length,d=b.pop(),e=b.length,f={
            url:d,
            origUrl:d,
            prefixes:b
        },g,h;
        for(h=0;h<e;h++)g=F[b[h]],g&&(f=g(f));
        for(h=0;h<c;h++)f=E[h](f);
        return f
        }
        function e(a,b,e,g,h){
        var i=f(a),j=i.autoCallback;
        if(!i.bypass){
            b&&(b=D(b)?b:b[a]||b[g]||b[a.split("/").pop().split("?")[0]]);
            if(i.instead)return i.instead(a,b,e,g,h);
            e.load(i.url,i.forceCSS||!i.forceJS&&/css$/.test(i.url)?"c":c,i.noexec),(D(b)||D(j))&&e.load(function(){
                d(),b&&b(i.origUrl,h,g),j&&j(i.origUrl,h,g)
                })
            }
        }
    function b(a,b){
    function c(a){
        if(C(a))e(a,h,b,0,d);
        else if(B(a))for(i in a)a.hasOwnProperty(i)&&e(a[i],h,b,i,d)
            }
            var d=!!a.test,f=d?a.yep:a.nope,g=a.load||a.both,h=a.callback,i;
    c(f),c(g),a.complete&&b.load(a.complete)
    }
    var g,h,i=this.yepnope.loader;
if(C(a))e(a,0,i,0);
    else if(A(a))for(g=0;g<a.length;g++)h=a[g],C(h)?e(h,0,i,0):A(h)?H(h):B(h)&&b(h,i);else B(a)&&b(a,i)
    },H.addPrefix=function(a,b){
    F[a]=b
    },H.addFilter=function(a){
    E.push(a)
    },H.errorTimeout=1e4,b.readyState==null&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",G=function(){
    b.removeEventListener("DOMContentLoaded",G,0),b.readyState="complete"
    },0)),a.yepnope=d()
}(this,this.document),Modernizr.load=function(){
    yepnope.apply(window,[].slice.call(arguments,0))
    };

// ======================= DDD mini framework =============================== //

(function(){



    var DDD = {};
    // again, borrowed from PastryKit
    DDD.isTangible = !!('createTouch' in document);
    DDD.CursorStartEvent = DDD.isTangible ? 'touchstart' : 'mousedown';
    DDD.CursorMoveEvent = DDD.isTangible ? 'touchmove' : 'mousemove';
    DDD.CursorEndEvent = DDD.isTangible ? 'touchend' : 'mouseup';

    // get i.e. 'WebkitTransform'
    var transformProp = Modernizr.prefixed('transform');

    /* ==================== EventHandler ==================== */

    DDD.EventHandler = function() {};

    DDD.EventHandler.prototype.handleEvent = function( event ) {
        if ( this[event.type] ) {
            this[event.type](event);
        }
    };


    /* ==================== RangeDisplay ==================== */

    // displays the value of a range input
    // why isn't this in the HTML5 spec?

    DDD.RangeDisplay = function ( range ) {
        this.range = range;
        this.output = document.createElement('span');
        this.output.addClassName('range-display');
  
  
        this.units = this.range.getAttribute('data-units') || '';
  
        // this.output.textContent = this.range.value;
        this.change();
  
  
        this.range.parentNode.appendChild( this.output );
  
        this.range.addEventListener( 'change', this, false);
    };

    DDD.RangeDisplay.prototype = new DDD.EventHandler();

    DDD.RangeDisplay.prototype.change = function( event ) {
        this.output.textContent = this.range.value + this.units;
    };


    /* ==================== ProxyRange ==================== */

    // polyfill for range inputs
    // by no means a production-ready solution, but it'll do for these demos

    DDD.ProxyRange = function ( input ) {
        this.input = input;
  
        this.slider = document.createElement('div');
        this.slider.addClassName('proxy-range');

        this.handle = document.createElement('div');
        this.handle.addClassName('handle');
        this.slider.appendChild( this.handle );


        this.width = parseInt( getComputedStyle( this.input ).width, 10);
        this.slider.style.width = this.width + 'px';
  
        this.min = parseInt( this.input.getAttribute('min') || 0, 10 );
        this.max = parseInt( this.input.getAttribute('max') || 100, 10 );
  
        this.normalizeRatio = ( this.max - this.min ) / ( this.width - DDD.ProxyRange.lineCap * 2 );
  
        this.value = this.input.value;

        this.resetHandlePosition();
  
        this.slider.addEventListener( DDD.CursorStartEvent, this, false );
        this.handle.addEventListener( DDD.CursorStartEvent, this, false );
  
        this.input.parentNode.insertBefore( this.slider, this.input.nextSibling );
        this.input.style.display = 'none';
  
        this.x = this.slider.offsetLeft;
  
    };

    // constant for position the handle inside the slider
    DDD.ProxyRange.lineCap = 15;

    DDD.ProxyRange.prototype = new DDD.EventHandler();

    DDD.ProxyRange.prototype.moveHandle = function( event ) {
        var cursor = DDD.isTangible ? event.touches[0] : event,
        x = cursor.pageX - this.x;
        x = Math.max( DDD.ProxyRange.lineCap, Math.min( this.width - DDD.ProxyRange.lineCap, x ) );
  
        this.positionHandle( x );
  
        this.value = Math.round( ( x - DDD.ProxyRange.lineCap ) * this.normalizeRatio + this.min );
  
        if ( this.input.value != this.value ) {
            this.input.value = this.value;

            // trigger change event
            var evt = document.createEvent("Event");
            evt.initEvent("change", true, true);
            this.input.dispatchEvent( evt );
        }

    };

    DDD.ProxyRange.prototype.positionHandle = function( x ) {
        this.handle.style[ transformProp ] =  DDD.translate( x, 0 );
    };

    DDD.ProxyRange.prototype.resetHandlePosition = function() {
        var x = ( this.value - this.min ) / this.normalizeRatio + DDD.ProxyRange.lineCap;
        this.positionHandle( x );
    };


    DDD.ProxyRange.prototype[ DDD.CursorStartEvent ] = function( event ) {
        this.slider.addClassName('highlighted');
  
        this.moveHandle( event );
  
        window.addEventListener( DDD.CursorMoveEvent, this, false );
        window.addEventListener( DDD.CursorEndEvent, this, false );
  
        event.preventDefault();
    };

    DDD.ProxyRange.prototype[ DDD.CursorMoveEvent ] = function( event ) {
  
        this.moveHandle( event );
  
        event.preventDefault();
    };

    DDD.ProxyRange.prototype[ DDD.CursorEndEvent ] = function( event ) {
  
        this.slider.removeClassName('highlighted');
  
        window.removeEventListener( DDD.CursorMoveEvent, this, false );
        window.removeEventListener( DDD.CursorEndEvent, this, false );
    };


    /* ==================== Test 3D transform support ==================== */

    DDD.translate = Modernizr.csstransforms3d ?
    function( x, y ) {
        return 'translate3d(' + x + 'px, ' + y + 'px, 0 )';
    } :
    function( x, y ) {
        return 'translate(' + x + 'px, ' + y + 'px)';
    };


    /* ==================== Start Up ==================== */


    DDD.init = function() {
  
        var ranges = document.querySelectorAll('input[type="range"]'),
        rangesLen = ranges.length,
        i;
  
        if ( rangesLen ) {
    
            // create range output display
            for ( i=0; i < rangesLen; i++ ) {
                new DDD.RangeDisplay( ranges[i] );
            }
    
            // check browser support for range input
            // this has been hacked together from Modernizr range input test
            // -> Thanks Faruk Ates, Paul Irish, and Mike Taylor http://modernizr.com
            var isRangeSupported = (function() {
                var isSupported = ranges[0].type !== 'text';
                if ( isSupported ) {
                    var appearanceProp = Modernizr.prefixed('appearance');
                    isSupported = getComputedStyle( ranges[0] )[ appearanceProp ] !== 'textfield';
                }
                return isSupported;
            })();
    
            // create range inputs for iOS
            if ( !isRangeSupported ) {
                for ( i=0; i < rangesLen; i++ ) {
                    new DDD.ProxyRange( ranges[i] );
                }
            }
    
        }
  
    };


    window.addEventListener( 'DOMContentLoaded', DDD.init, false);

    // put in global namespace
    window.DDD = DDD;

})();
